import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:provider/provider.dart';
import 'package:dartssh2/dartssh2.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:convert';
import 'package:logger/logger.dart';
// import 'package:scpdemo/main1.dart';

// 初始化 Logger
final logger = Logger();

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => TransferProvider(),
      child: const MyApp(),
    ),
  );
  configLoading();
}

/// 配置 `EasyLoading`
void configLoading() {
  EasyLoading.instance
    ..loadingStyle = EasyLoadingStyle.dark
    ..indicatorType = EasyLoadingIndicatorType.fadingCircle
    ..maskType = EasyLoadingMaskType.black
    ..userInteractions = false;
}

/// 应用主界面
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'SCP 传输工具',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const SCPTransferScreen(),
      builder: EasyLoading.init(),
    );
  }
}

/// 传输任务数据模型
class TransferTask {
  String id;
  String remotePath;
  String localPath;
  double progress;
  String status;

  TransferTask({
    required this.id,
    required this.remotePath,
    required this.localPath,
    this.progress = 0.0,
    this.status = "等待",
  });
}

/// 传输任务 Provider
class TransferProvider with ChangeNotifier {
  final List<TransferTask> _tasks = [];

  List<TransferTask> get tasks => _tasks;

  void addTask(TransferTask task) {
    _tasks.add(task);
    notifyListeners();
  }

  void updateTaskProgress(String taskId, double progress, String status) {
    var task = _tasks.firstWhere((t) => t.id == taskId);
    task.progress = progress;
    task.status = status;
    notifyListeners();
  }

  void completeTask(String taskId) {
    var task = _tasks.firstWhere((t) => t.id == taskId);
    task.status = "完成";
    task.progress = 100.0;
    notifyListeners();
  }

  void failTask(String taskId, String error) {
    var task = _tasks.firstWhere((t) => t.id == taskId);
    task.status = "失败: $error";
    notifyListeners();
  }
}

/// SCP 传输界面
class SCPTransferScreen extends StatefulWidget {
  const SCPTransferScreen({super.key});

  @override
  _SCPTransferScreenState createState() => _SCPTransferScreenState();
}

class _SCPTransferScreenState extends State<SCPTransferScreen> {
  final TextEditingController _remoteHostController = TextEditingController();
  final TextEditingController _remoteUserController = TextEditingController();
  final TextEditingController _remotePasswordController = TextEditingController();
  final List<TextEditingController> _remotePaths = [];
  String _localPath = "";

  /// 选择本地保存路径
  Future<void> _selectLocalPath() async {
    Directory directory = await getApplicationDocumentsDirectory();
    setState(() {
      _localPath = directory.path;
    });
  }

  /// 获取远程文件大小
  Future<int> _getRemoteFileSize(SSHClient client, String remotePath) async {
    try {
      var response = await client.run('stat -c %s $remotePath');
      // 将 Uint8List 解码为字符串
      String responseString = utf8.decode(response);
      return int.tryParse(responseString.trim()) ?? 0;
    } catch (e) {
      logger.e("获取远程文件大小失败: $e");
      return 0;
    }
  }

  /// 验证主机地址是否合法
  bool isValidHost(String host) {
    final regex = RegExp(r'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-zA-Z]{2,}$');
    return regex.hasMatch(host);
  }

  /// 手动实现 SCP 下载功能
  Future<void> manualSCPDownload(SSHClient client, String remotePath, IOSink fileSink, String taskId, int totalSize, TransferProvider provider) async {
    int transferredBytes = 0;
    try {
      var session = await client.shell();
      session.write(utf8.encode('scp -f $remotePath\n'));

      // 创建一个可广播的流
      final broadcastStream = session.stdout.asBroadcastStream();

      var responseHeader = await broadcastStream.first;
      if (responseHeader[0] == 1) {
        var errorMessage = utf8.decode(responseHeader.sublist(1));
        logger.e("SCP 命令执行失败: $errorMessage");
        throw Exception("SCP 命令执行失败: $errorMessage");
      }

      await for (var data in broadcastStream) {
        fileSink.add(data);
        transferredBytes += data.length;
        double progress = (transferredBytes / totalSize) * 100;
        provider.updateTaskProgress(taskId, progress, "传输中");
      }
      await fileSink.flush();
    } catch (e) {
      logger.e("手动 SCP 下载失败: $e");
      rethrow;
    }
  }

  /// 启动批量下载
  Future<void> startBatchDownload() async {
    final provider = Provider.of<TransferProvider>(context, listen: false);
    String remoteHost = _remoteHostController.text;
    String username = _remoteUserController.text;
    String password = _remotePasswordController.text;

    if (!isValidHost(remoteHost) || username.isEmpty || _localPath.isEmpty || _remotePaths.isEmpty) {
      EasyLoading.showError("请填写有效的信息");
      return;
    }

    EasyLoading.show(status: "连接服务器...");

    SSHClient? client;
    try {
      client = SSHClient(
        await SSHSocket.connect(remoteHost, 22),
        username: username,
        onPasswordRequest: () => password,
      );
      EasyLoading.showSuccess("连接成功");

      for (var controller in _remotePaths) {
        String remotePath = controller.text;
        String localFilePath = "$_localPath/${remotePath.split('/').last}";

        TransferTask task = TransferTask(
          id: DateTime.now().millisecondsSinceEpoch.toString(),
          remotePath: remotePath,
          localPath: localFilePath,
        );
        provider.addTask(task);

        final file = File(localFilePath).openWrite();
        try {
          int totalSize = await _getRemoteFileSize(client, remotePath);
          if (totalSize == 0) throw Exception("无法获取文件大小");

          await manualSCPDownload(client, remotePath, file, task.id, totalSize, provider);

          provider.completeTask(task.id);
          EasyLoading.showSuccess("文件 ${task.remotePath} 下载成功");
        } catch (e) {
          logger.e("下载任务失败: $e");
          provider.failTask(task.id, e.toString());
        } finally {
          await file.close();
        }
      }
    } catch (e) {
      if (e is SocketException) {
        EasyLoading.showError("网络连接失败: $e");
      } else if (e is AuthenticationException) {
        EasyLoading.showError("认证失败: $e");
      } else {
        EasyLoading.showError("连接失败: $e");
      }
    } finally {
      client?.close();
    }
  }

  /// 添加新的远程路径输入框
  void addRemotePathField() {
    setState(() {
      _remotePaths.add(TextEditingController());
    });
  }

  @override
  Widget build(BuildContext context) {
    final provider = Provider.of<TransferProvider>(context);

    return Scaffold(
      appBar: AppBar(title: const Text("SCP 传输工具")),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(controller: _remoteHostController, decoration: const InputDecoration(labelText: "远程主机")),
            TextField(controller: _remoteUserController, decoration: const InputDecoration(labelText: "远程用户")),
            TextField(controller: _remotePasswordController, decoration: const InputDecoration(labelText: "远程密码"), obscureText: true),
            const SizedBox(height: 10),
            ElevatedButton(onPressed: _selectLocalPath, child: const Text("选择本地路径")),
            Text("本地路径: $_localPath", style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
            const SizedBox(height: 10),
            ..._remotePaths.map((controller) => TextField(controller: controller, decoration: const InputDecoration(labelText: "远程路径"))),
            ElevatedButton(onPressed: addRemotePathField, child: const Text("添加远程路径")),
            const SizedBox(height: 10),
            ElevatedButton(onPressed: startBatchDownload, child: const Text("开始下载")),
            Expanded(
              child: ListView.builder(
                itemCount: provider.tasks.length,
                itemBuilder: (context, index) {
                  var task = provider.tasks[index];
                  return ListTile(
                    title: Text(task.remotePath),
                    subtitle: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text("${task.progress.toStringAsFixed(2)}% - ${task.status}"),
                        LinearProgressIndicator(
                          value: task.progress / 100,
                        ),
                      ],
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class AuthenticationException implements Exception {
  final String message;
  AuthenticationException(this.message);

  @override
  String toString() {
    return 'AuthenticationException: $message';
  }
}
